iT邦幫忙

2026 iThome 鐵人賽

DAY 18
0
JavaScript

JavaScript為什麼筆記本系列 第 18

Day 18|React 怎麼知道要顯示哪個畫面?

  • 分享至 

  • xImage
  •  

Day 17 最後,我們把登入流程接成這樣:

import { useState } from 'react'

function App() {
  const [user, setUser] = useState(null)

  function login() {
    setUser({
      name: 'Anthony'
    })
  }

  return (
    <div>
      <p>
        {user ? `Hello, ${user.name}` : '尚未登入'}
      </p>

      <button onClick={login}>
        Sign In
      </button>
    </div>
  )
}

export default App

前兩天我都把注意力放在:

useState
onClick
login
setUser

但其實上面還有一行,我一直在用,卻沒有真的拆過:

{user ? `Hello, ${user.name}` : '尚未登入'}

這行很神奇。

user 一開始是:

null

登入後卻變成:

{
  name: 'Anthony'
}

它根本不是:

true
false

那 JavaScript 到底是在判斷什麼?


先給最短答案:不是 React 在猜,是 JavaScript 先選好結果

先把 JSX 拿掉,看最普通的 JavaScript:

user ? '已登入' : '尚未登入'

這叫做 ternary operator(三元運算子)。

先用人話讀就好:

條件 ? 條件成立時的結果 : 條件不成立時的結果

所以:

user ? '已登入' : '尚未登入'

其實是在問:

user 現在如果被 JavaScript 判斷成成立,就選左邊;不成立,就選右邊。

React 沒有發明這個判斷方式。

JavaScript 先把 ternary 算出結果,React 再把那個結果 render 出來。


可是 user 又不是 boolean,為什麼可以判斷?

這就是我真正卡住的地方。

如果是這樣,我很好懂:

const isLoggedIn = true

isLoggedIn ? '已登入' : '尚未登入'

因為 isLoggedIn 本來就是 boolean。

但我們現在是:

const [user, setUser] = useState(null)

後來:

setUser({
  name: 'Anthony'
})

所以 user 可能是:

null

也可能是一個 Object:

{ name: 'Anthony' }

JavaScript 在需要做條件判斷時,會把這些值看成「像 false」或「像 true」。

常看到兩個詞:

falsy
truthy

今天先不用背完整清單。

只看會員系統現在真的會遇到的兩個值:

null
→ falsy
→ 條件判斷時當成不成立

Object
→ truthy
→ 條件判斷時當成成立

所以:

user ? '已登入' : '尚未登入'

在這兩種狀態下其實就是:

user = null
↓
選右邊
↓
尚未登入

以及:

user = { name: 'Anthony' }
↓
選左邊
↓
已登入

原來不需要另外再存一個:

const isLoggedIn = true

因為「user 有沒有資料」本身就已經可以拿來表示現在有沒有登入。


再看一次那行 JSX,就比較好理解了

原本:

<p>
  {user ? `Hello, ${user.name}` : '尚未登入'}
</p>

大括號:

{ ... }

代表我要在 JSX 裡放一個 JavaScript expression。

裡面的:

user ? `Hello, ${user.name}` : '尚未登入'

會先算出其中一個結果。

如果:

user === null

那結果是:

尚未登入

如果:

user = {
  name: 'Anthony'
}

那結果變成:

Hello, Anthony

所以 React 最後收到的不是「一個神祕的判斷式」。

而是 JavaScript 已經選好的結果。


這次不要只換文字,直接換整塊畫面

如果條件渲染只能拿來切換一行字,好像還沒什麼感覺。

真正做會員系統時,我想要的是:

未登入
→ 顯示登入區塊

已登入
→ 顯示會員區塊

可以直接寫:

import { useState } from 'react'

function App() {
  const [user, setUser] = useState(null)

  function login() {
    setUser({
      name: 'Anthony'
    })
  }

  function logout() {
    setUser(null)
  }

  return (
    <main>
      {user ? (
        <section>
          <h2>Hello, {user.name}</h2>
          <p>你已經登入會員系統。</p>

          <button onClick={logout}>
            Sign Out
          </button>
        </section>
      ) : (
        <section>
          <h2>尚未登入</h2>

          <button onClick={login}>
            Sign In
          </button>
        </section>
      )}
    </main>
  )
}

export default App

這次 ternary 左右兩邊不再只是字串。

而是兩塊 JSX。

可以把它直接讀成:

user 有資料嗎?

有
→ render 會員畫面

沒有
→ render 登入畫面

這就是「條件渲染」。


把 Day 16、17、18 串起來

現在前三天的東西終於可以連成一條。

Day 16:State

const [user, setUser] = useState(null)

回答:

React 現在要記住什麼資料?

Day 17:Event

<button onClick={login}>

回答:

使用者做了什麼事情之後,我才要改資料?

Day 18:Conditional Rendering

{user ? <Member /> : <Login />}

概念上回答:

資料不同時,我現在應該顯示哪一個畫面?

三個接起來就是:

state
user = null
↓
React render
↓
條件判斷 user
↓
顯示登入畫面
↓
使用者 click Sign In
↓
onClick 呼叫 login
↓
setUser({ name: 'Anthony' })
↓
state 改變
↓
React 再 render
↓
再次判斷 user
↓
這次 user 是 Object
↓
顯示會員畫面

以前看 React,我很容易只看到:

useState
onClick
? :

三坨不同的語法。

現在比較像是在看一條資料流。


那不用 ternary,寫 if 不行嗎?

可以。

例如先在 return 前面決定:

let content

if (user) {
  content = <p>Hello, {user.name}</p>
} else {
  content = <p>尚未登入</p>
}

return (
  <div>
    {content}
  </div>
)

這完全可以。

那為什麼 JSX 裡常看到 ternary?

因為這個:

user ? A : B

本身會產生一個值

所以很適合直接放進:

{ ... }

裡面。

if 比較像是在控制程式流程,不是直接產生一個可以塞進 JSX 的值。

所以這樣不能直接寫:

{
  if (user) {
    <Member />
  } else {
    <Login />
  }
}

這不是「React 討厭 if」。

而是 JSX 的大括號這個位置要的是 JavaScript expression。

ternary 剛好是 expression,所以很好放。

這又是一次「看起來像 React,其實裡面藏的是 JavaScript」。


!user 又是在幹嘛?

會員選單有時會看到:

if (!user) {
  return null
}

! 可以先讀成「不是」。

但更接近現在情境的讀法是:

user
→ 有會員資料嗎?

!user
→ 沒有會員資料嗎?

所以:

user = null

時:

!user

會得到 true

於是我們甚至可以做:

function MemberMenu({ user }) {
  if (!user) {
    return null
  }

  return (
    <nav>
      <a href="/member">會員中心</a>
    </nav>
  )
}

這裡的:

return null

可以先理解成:

這個 Component 這次不要顯示任何東西。

不過要注意一件很重要的事:

把「會員中心」藏起來,只是 UI 顯示邏輯,不等於真的完成權限保護。

真正的登入驗證和權限控制是後面的問題,今天先不要混在一起。


最容易搞錯的地方

1. ternary 是 React 語法?

不是。

這個:

condition ? A : B

本來就是 JavaScript。

React 只是常常把它放進 JSX:

{condition ? <A /> : <B />}

2. 條件一定要是 truefalse

不一定。

JavaScript 做條件判斷時會看 truthy / falsy。

今天我們只需要先記:

null
→ falsy

Object
→ truthy

這剛好就能讓會員資料同時扮演:

會員是誰
+
現在有沒有人登入

3. setUser 自己把畫面改掉了?

不是直接去改某個 <p><section>

比較像:

setUser
↓
state 更新
↓
React 再 render
↓
JavaScript 再跑一次條件判斷
↓
這次選到另一塊 JSX

所以畫面改變,是整條流程的結果。


如果今天只記得一件事

我會記這一句:

條件渲染不是 React 在「猜」要顯示什麼,而是 JavaScript 先根據目前的資料選出結果,React 再把那個結果 render 出來。

放回今天的會員系統:

{user ? <Member /> : <Login />}

可以直接讀成:

有 user
→ Member

沒有 user
→ Login

醬子



上一篇
Day 17|onClick={login} 為什麼不用寫成 login()?
下一篇
Day 19|&& 明明是邏輯運算子,為什麼可以拿來顯示 React 元件?
系列文
JavaScript為什麼筆記本20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言